package cn.minimelon.solon.service.system.thread;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.minimelon.solon.service.system.Spd2BaseService;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.Solon;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 并行计算写入Excel处理类，仅适合单Sheet页的写入
 * 
 * @param <E>
 * 数据对象类型，必须是Map集合
 */
@Slf4j
public class ExcelHandler<E> {
    private static final String TIME_FMT = "%s-%02d-01 00:00:00";
    private final String serviceId; // 服务ID
    private final Integer year; // 年份
    private static final int THREAD_COUNT = 4; // 启动的线程数

    /**
     * 处理某一年的数据
     *
     * @param year 年份
     */
    public ExcelHandler(Integer year, String serviceId) {
        this.year = year;
        this.serviceId = serviceId;
    }

    /**
     * 执行多线程处理写操作
     */
    public void multiThreadWrite() {
        ExecutorService executor = Executors.newCachedThreadPool(); // 线程池
        try {
            int num = 12 / THREAD_COUNT; // 每个线程平均处理的数据量
            CountDownLatch doneSignal = new CountDownLatch(THREAD_COUNT); // 计数栅栏
            // THREAD_COUNT - 1个线程的数据处理
            for (int i = 1; i < THREAD_COUNT; i++) {
                executor.submit(new ExcelWriter<E>(doneSignal, this, serviceId, (i - 1) * num, num * i));
            }
            // 最后一个线程
            executor.submit(new ExcelWriter<E>(doneSignal, this, serviceId, (THREAD_COUNT - 1) * num, 12));
            doneSignal.await(); // 等待所有线程完成sheet操作
            log.error("multiThreadWrite完成处理");
        } catch (Exception ex) {
            log.error("未知错误", ex);
        } finally {
            executor.shutdown(); // 执行器关闭，主线程结束
        }
    }

    /**
     * 为指定的月份，初始化数据
     * 
     * @param serviceId 处理服务
     * @param index 月份-1
     */
    public void writeRowContent(String serviceId, int index) {
        int month = index + 1;
        log.info("服务:{} 月份：{}", serviceId, month);
        Spd2BaseService spd2DistrService = Solon.context().getBean(serviceId);
        if (spd2DistrService != null) {
            String startStr = String.format(TIME_FMT, year, month);
            DateTime startTime = DateUtil.parseDateTime(startStr);
            DateTime nextEnd = DateUtil.offset(startTime, DateField.MONTH, 1);
            String settleMonth = String.format("%s%02d", year, month);
            log.error("发票明细, 按月份：{} 开始处理", settleMonth);
            for (int i = 0; i <= 4; i++) {
                DateTime endTime1 = DateUtil.offset(startTime, DateField.DAY_OF_MONTH, i * 8);
                DateTime endTime2 = DateUtil.offset(startTime, DateField.DAY_OF_MONTH, (i + 1) * 8);
                if (endTime2.after(nextEnd)) {
                    endTime2 = nextEnd;
                }
                log.error("月份：{} 时间:{} ~ {}, 开始处理", settleMonth, endTime1, endTime2);
                spd2DistrService.insertMonthRangeSplit(endTime1, endTime2, settleMonth);
            }
        }
    }
}
